package com.caits.lbs.framework.services.mina;

import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.HashMap;

import org.apache.log4j.Logger;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.filterchain.IoFilter;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

import com.caits.lbs.framework.log.CommonLogFactory;

/**
 * 
 * 此类完成客户端与服务端的连接
 * 实现多个目标地址连接，处理器注入
 * 完成网络中断后自动重连
 */

public class MinaConnectorClient extends Thread {

	private static final IoFilter LOGGING_FILTER = new LoggingFilter();

	private static final IoFilter CODEC_FILTER = new ProtocolCodecFilter(
			new TextLineCodecFactory());

	/** TODO */
	private Logger log = CommonLogFactory.getLog();
	
	/** 当前使用的连接实例 */
	private static NioSocketConnector socket;

	/** 全局连接对象 */
	public static HashMap<Integer, ConnectFuture> _connect = new HashMap<Integer, ConnectFuture>();

	private String ipAddr = "";

	private String ip = "";

	private String port = "";

	/** 实例的序号 */
	private int index = 0 ;

	/**  检测连接间隔时间(ms) */
	private int NOOPTIME=10000;

	/** 断线重连时间(ms) */
	private int RECONNECTTIME=3000;
	
	/** 发送数据轮询的当前序号 */
	private static int currentIndex = 0;

	/** 处理句柄 */
	private  static IoHandler ioHandler = null;
	
	/**
	 * 构造器 
	 */
	public MinaConnectorClient() {}
	
	/**
	 * 带索引的构造器
	 * @param i 
	 */
	public MinaConnectorClient(int i) {
		index = i;
	}

	public void init() {
		// 启动监听服务
		//MinaAcceptorServer server = new MinaAcceptorServer();
		//server.startup();

		String[] str = ipAddr.split(";");
		for (int i = 0; i < str.length; i++) {
			String ip = str[i].split(":")[0];
			String port = str[i].split(":")[1];
			MinaConnectorClient dtf = new MinaConnectorClient(i);
			dtf.setIp(ip);
			dtf.setPort(port);
			dtf.start();
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	private static ConnectFuture socketConnect(String ip, String port,IoHandler handler) {

		socket = new NioSocketConnector();
		
		socket.setHandler(handler);// // 指定业务逻辑处理器

		// 配置过滤器
		DefaultIoFilterChainBuilder chain = socket.getFilterChain();
		// 增加日志过滤器
		chain.addLast("logger", LOGGING_FILTER);
		// 增加字符编码过滤器
		// chain.addLast("codec", CODEC_FILTER);

		// chain.addLast("mdc", new MdcInjectionFilter());
		//chain.addLast("ObjectData", new ProtocolCodecFilter(new TextLineCodecFactory()));
		chain.addLast("ObjectData", CODEC_FILTER);
//		socket.getFilterChain().addLast("ThreadPool",
//				new ExecutorFilter(Executors.newCachedThreadPool()));
		// socket.getFilterChain().addLast("threadPool",new ExecutorFilter(new
		// OrderedThreadPoolExecutor()));// 设置线程池，以支持多线程
		socket.getSessionConfig().setReadBufferSize(4096);
		// session空闲60秒给服务器发空闲的信息，即心跳信息
//		socket.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 60);

		ConnectFuture future = socket.connect(new InetSocketAddress(ip, Integer
				.parseInt(port)));
		future.awaitUninterruptibly();

		return future;
	}

	public void run() {

		
		ConnectFuture _socketConnect;
		_socketConnect = socketConnect(ip, port,getIoHandler());

		while (true) {

			boolean socketConnect = _socketConnect.isConnected();

			if (socketConnect) {

				try {

					_connect.put(index, _socketConnect);

					Thread.sleep(NOOPTIME);

					log.debug(ip + ":" + port + "网络成功连接，10秒后，重新检测");

					log.debug("CurrentSize:" + _connect.size());

				} catch (InterruptedException e) {

					e.printStackTrace();

				}

			} else {

				log.debug(ip + ":" + port
						+ "客户端未成功连接到服务器上，每隔3秒重新与服务器连接！");

				try {

					Thread.sleep(RECONNECTTIME);

					_socketConnect = socketConnect(ip, port,getIoHandler());

				} catch (InterruptedException e) {

					e.printStackTrace();

				}

			}

		}

	}

	public void startup() {

		this.start();

	}

	public void shutdown() {

		this.interrupt();

		this.close();

	}

	/**
	 * 
	 * 关闭socket通道
	 */

	private void close() {

		if (socket.isActive()) {

			socket.dispose();

		}

	}

	public String getIp() {
		return ip;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

	public String getPort() {
		return port;
	}

	public void setPort(String port) {
		this.port = port;
	}

	public String getIpAddr() {
		return ipAddr;
	}

	public void setIpAddr(String ipAddr) {
		this.ipAddr = ipAddr;
	}

	/**
	 * 发送时采用轮询机制 
	 * @param cmd
	 */
	public static void sentData(String cmd){
		_connect.get(currentIndex).getSession().write(cmd);
		currentIndex++;
		if(currentIndex==_connect.size())currentIndex=0;
		
	}
	
	/**
	 * 释放连接资源 
	 */
	public void release(){
		Collection<ConnectFuture> it = _connect.values();
		for(ConnectFuture future : it){
			ClientIoHandler handler = (ClientIoHandler)future.getSession().getHandler();
			String logout = handler.getClient().logout();
			future.getSession().write(logout);
			future.getSession().close();
		}
		if(_connect!=null)_connect.clear();
	}

	/**
	 * 设置属性 ioHandler 的值，IoHandler类型
	 * @param ioHandler the ioHandler to set
	 */
	public void setIoHandler(IoHandler handler) {
		if(ioHandler==null)
		ioHandler = handler;
	}

	/**
	 * 获取属性ioHandler的值
	 * @return the ioHandler : IoHandler
	 */
	public IoHandler getIoHandler() {
		return ioHandler;
	}
	
	/**
	 * 测试类 
	 * @param args
	 */
	public static void main(String[] args){
		//60.29.137.10:7002
		String address="211.157.99.17:20036";
		MinaConnectorClient mcc = new MinaConnectorClient();
		mcc.setIpAddr(address);
		ClientIoHandler handle = new ClientIoHandler();
		MonitorClientImpl client = new MonitorClientImpl();
		handle.setClient(client);
		mcc.setIoHandler(handle);
		mcc.init();
	}
}